package da.metricscraft.client.tools;

import java.util.HashMap;
import java.util.ArrayList;
import java.util.Map.Entry;

import da.metricscraft.client.threads.PlayerXMLLoader.PlayerDataType;
import da.metricscraft.client.threads.PlayerXMLLoader.PlayerStatsStruct;

public class Classifier {
	private static HashMap<Classification, Float> calculatedValues;
	private static HashMap<PlayerStatsStruct, Float> buildStruct(String classifier){
		HashMap<PlayerStatsStruct, Float> list = null;
		if(classifier == "explorer"){
			list = new HashMap<PlayerStatsStruct, Float>();
			list.put(new PlayerStatsStruct(PlayerDataType.RUNTIME, 0.8f),0.37f); 
			list.put(new PlayerStatsStruct(PlayerDataType.SPRINTTIME, 0.05f),0.02f);
			list.put(new PlayerStatsStruct(PlayerDataType.SWIMTIME, 0.1f),0.15f);
			list.put(new PlayerStatsStruct(PlayerDataType.CHUNKS_DISCOVERED, 100),0.40f);
			list.put(new PlayerStatsStruct(PlayerDataType.DAMAGE_TAKEN_FALL, 0.1f),0.02f);
			list.put(new PlayerStatsStruct(PlayerDataType.DAMAGE_TAKEN_STARVATION, 0.1f),0.04f);
		}else if (classifier == "dungeonrunner"){
			list = new HashMap<PlayerStatsStruct, Float>();
			list.put(new PlayerStatsStruct(PlayerDataType.RUNTIME, 0.4f), 0.2f);
			list.put(new PlayerStatsStruct(PlayerDataType.JUMPS, 5f), 0.04f);
			list.put(new PlayerStatsStruct(PlayerDataType.UNDERGROUNDTIME, 0.5f), 0.22f);
			list.put(new PlayerStatsStruct(PlayerDataType.MININGTIME, 0.5f), 0.15f);
			list.put(new PlayerStatsStruct(PlayerDataType.MINED, 10f), 0.15f);
			list.put(new PlayerStatsStruct(PlayerDataType.FINE_MINED, 2f), 0.08f);
			list.put(new PlayerStatsStruct(PlayerDataType.KILLS, 0.2f), 0.08f);
			list.put(new PlayerStatsStruct(PlayerDataType.HEALTH_REGAINED, 1f), 0.02f);
			list.put(new PlayerStatsStruct(PlayerDataType.DAMAGE_TAKEN_ENTITY_ATTACK, 0.4f), 0.03f);
			list.put(new PlayerStatsStruct(PlayerDataType.DAMAGE_TAKEN_ENTITY_EXPLOSION, 0.4f), 0.03f);
		}else if (classifier == "builder"){
			list = new HashMap<PlayerStatsStruct, Float>();
			list.put(new PlayerStatsStruct(PlayerDataType.CROUCHTIME, 0.02f), 0.05f);
			list.put(new PlayerStatsStruct(PlayerDataType.JUMPS, 4f), 0.05f);
			list.put(new PlayerStatsStruct(PlayerDataType.BUILT, 6f), 0.8f);
			list.put(new PlayerStatsStruct(PlayerDataType.CHESTS_OPENED, 0.2f), 0.05f);
			list.put(new PlayerStatsStruct(PlayerDataType.DAMAGE_TAKEN_FALL, 0.05f), 0.05f);
		}else if (classifier == "engineer"){
			list = new HashMap<PlayerStatsStruct, Float>();
			list.put(new PlayerStatsStruct(PlayerDataType.DEVELOP, 5f), 0.6f);
			list.put(new PlayerStatsStruct(PlayerDataType.DEVELOP_REMOVE, 0.1f), 0.2f);
			list.put(new PlayerStatsStruct(PlayerDataType.BUTTONS_PRESSED, 1f), 0.2f);
		}
		return list;
	}
	public static enum Classification{
		EXPLORER(new HashMap<PlayerStatsStruct, Float>(buildStruct("explorer"))),
		DUNGEON_RUNNER(new HashMap<PlayerStatsStruct, Float>(buildStruct("dungeonrunner"))),
		BUILDER(new HashMap<PlayerStatsStruct, Float>(buildStruct("builder"))),
		ENGINEER(new HashMap<PlayerStatsStruct, Float>(buildStruct("engineer")));
		
		public HashMap<PlayerStatsStruct, Float> list;
		private Classification(HashMap<PlayerStatsStruct, Float> list){
			this.list = list;
		}
		private float compare(float preset, float value){
			float deviation = 0;
			deviation = (preset - value)/preset;
			return deviation;
		}
		public ArrayList<PlayerStatsStruct> getDeviation(ArrayList<PlayerStatsStruct> playerData){
			ArrayList<PlayerStatsStruct> retValue = new ArrayList<PlayerStatsStruct>();
			for(Entry<PlayerStatsStruct, Float> currentCheck : list.entrySet()){
				System.out.println("Comparing " + currentCheck.getKey());
				boolean checked = false;
				for (PlayerStatsStruct currentPlayerData : playerData){
					if (currentCheck.getKey().type == currentPlayerData.type){
						//weight values (getValue())
						System.out.println(" | " + currentPlayerData.floatValue() + "/" + currentCheck.getKey().floatValue() + " : " + compare(currentCheck.getKey().floatValue(), currentPlayerData.floatValue()) * currentCheck.getValue());
						
						retValue.add(new PlayerStatsStruct(currentPlayerData.type, compare(currentCheck.getKey().floatValue(), currentPlayerData.floatValue()) * currentCheck.getValue()));
						checked = true;
						break;
					}
				}
				if (!checked){
					System.out.println(" | 0" + "/" + currentCheck.getKey().floatValue() + " : " + compare(currentCheck.getKey().floatValue(), 0) * currentCheck.getValue());
					retValue.add(new PlayerStatsStruct(currentCheck.getKey().type, compare(currentCheck.getKey().floatValue(), 0) * currentCheck.getValue()));
				}
			}
			return retValue;
		}
		
	}
	
	private static ArrayList<PlayerStatsStruct> classificationData;
	
	
	public static void loadData(ArrayList<PlayerStatsStruct> data){
		calculatedValues = null;
		Classifier.classificationData = data;
	}
	public static HashMap<Classification, Float> calculate(){
		if (calculatedValues == null){
			HashMap<Classification, Float> retValue = new HashMap<Classifier.Classification, Float>();
			System.out.println("---EXPLORER---");
			retValue.put(Classification.EXPLORER, (1 - getFullDeviation(Classification.EXPLORER)));
			System.out.println("---DUNGEON RUNNER---");
			retValue.put(Classification.DUNGEON_RUNNER, (1 - getFullDeviation(Classification.DUNGEON_RUNNER)));
			System.out.println("---BUILDER---");
			retValue.put(Classification.BUILDER, (1 - getFullDeviation(Classification.BUILDER)));
			System.out.println("---ENGINEER---");
			retValue.put(Classification.ENGINEER, (1 - getFullDeviation(Classification.ENGINEER)));
			calculatedValues = retValue;
			return retValue;
		}else return calculatedValues;
	}
	private static float getFullDeviation(Classification c){
		float sumdeviation = 0;
		ArrayList<PlayerStatsStruct> deviations = c.getDeviation(classificationData);
		switch(c){
		case DUNGEON_RUNNER:
			for (PlayerStatsStruct pss : deviations){
				float value = pss.floatValue();
				//ignore if values are higher than expected
				if (pss.type == PlayerDataType.UNDERGROUNDTIME || pss.type == PlayerDataType.DAMAGE_TAKEN_ENTITY_ATTACK || pss.type == PlayerDataType.DAMAGE_TAKEN_ENTITY_EXPLOSION || pss.type == PlayerDataType.MINED ){
					value = Math.max(0, pss.floatValue());
				}else{
					value = Math.abs(value);
				}
				sumdeviation += value;
			}
			break;
		case EXPLORER:
			for (PlayerStatsStruct pss : deviations){
				float value = pss.floatValue();
				if (pss.type == PlayerDataType.RUNTIME || pss.type == PlayerDataType.JUMPS){
					value = Math.max(0, pss.floatValue());
				}else{
					value = Math.abs(value);
				}
				sumdeviation += value;
			}
			break;
		case BUILDER:
			for (PlayerStatsStruct pss : deviations){
				float value = pss.floatValue();
				if (pss.type == PlayerDataType.JUMPS || pss.type == PlayerDataType.DAMAGE_TAKEN_FALL || pss.type == PlayerDataType.BUILT){
					value = Math.max(0, pss.floatValue());
				}else{
					value = Math.abs(value);
				}
				sumdeviation += value;
			}
			break;
		case ENGINEER:
			for (PlayerStatsStruct pss : deviations){
				float value = pss.floatValue();
				if (pss.type == PlayerDataType.DEVELOP_REMOVE || pss.type == PlayerDataType.BUTTONS_PRESSED){
					value = Math.max(0, pss.floatValue());
				}else{
					value = Math.abs(value);
				}
				sumdeviation += value;
			}
		}
		System.out.println("-full deviation: " + sumdeviation + "-");
		return sumdeviation;
	}
	public static HashMap<Classification, Float> getValuesOver(float percentage){
		HashMap<Classification, Float> retValue = new HashMap<Classifier.Classification, Float>();
		for (Entry<Classification, Float> entry : calculatedValues.entrySet()){
			if (entry.getValue() > percentage)
				retValue.put(entry.getKey(), entry.getValue());
		}
		return retValue;
	}
}
